{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "legislative-launch",
   "metadata": {},
   "source": [
    "# Python 面向对象编程"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "demonstrated-volunteer",
   "metadata": {},
   "source": [
    "在北宋时期，毕昇发明了活字印刷术。他先将文字做成一个个汉字模具，然后按照稿件把单字挑选出来，排列在字盘内，涂墨印刷成书，印完后再将字模拆出，留待下次排印时再次使用。活字印刷术相对于文字书写更加简洁高效，它对印刷业的兴起发挥了重大作用，甚至推动了欧洲文艺复兴的发展。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "incident-senegal",
   "metadata": {},
   "source": [
    "Python 是一种基于面向对象设计的编程语言，它使用“类”与“对象”进行编程。这里“类”就好比汉字模具，“对象”就好比印刷完的书籍。你不需要一次又一次书写复杂重复的程序，只需要提前编写好需要的类，然后通过类产生具有特定功能的对象即可，这大大提高了 Python 编程的简洁性。 "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "related-malawi",
   "metadata": {},
   "source": [
    "下面我们就通过面向对象的角度重新审视 Python 宇宙，相信你可以感受到面向对象带来的代码简化与效率提升。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "concerned-tuner",
   "metadata": {},
   "source": [
    "## 1.3.1 面向对象编程理论"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "exact-difficulty",
   "metadata": {},
   "source": [
    "在之前的代码中，我们往往采用典型的面向过程编程方式，定义很多函数与变量：\n",
    "\n",
    "    ## 定义函数：\n",
    "    函数1\n",
    "    函数2\n",
    "    函数3\n",
    "    函数4\n",
    "    \n",
    "    ## 定义变量：\n",
    "    变量1\n",
    "    变量2\n",
    "    变量3\n",
    "    变量4\n",
    "    \n",
    "    ## 通过变量与函数完成操作\n",
    "    变量3 = 函数1(变量1, 变量2)\n",
    "    变量5 = 函数2(变量3, 变量4)\n",
    "    \n",
    "然而当我们要实现的功能越来越复杂，需要添加的函数与变量也就越来越多。每个函数都有不同的功能，有特定的参数与返回结果，每个变量也有不同的表示意义，程序会变得越来越难以维护。而面向对象通过类与对象的方式解决问题：\n",
    "\n",
    "    ## 根据功能定义类1\n",
    "    类1：\n",
    "        类函数1\n",
    "    变量：\n",
    "        变量1\n",
    "        变量2\n",
    "    \n",
    "    ## 根据功能定义类2\n",
    "    类2：\n",
    "        类函数2\n",
    "        类函数3\n",
    "    变量：\n",
    "        变量3\n",
    "        变量4\n",
    "        变量5\n",
    "        \n",
    "    ## 通过对象完成操作\n",
    "    对象1 = 类1()\n",
    "    对象2 = 类2()\n",
    "    对象2.变量5 = 对象2.函数2(对象1.函数1())\n",
    "    \n",
    "    \n",
    "面向对象编程的出现，使得变量和函数可以根据功能进行整理分类，大大减轻了复杂程序的设计与维护负担。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "administrative-logging",
   "metadata": {},
   "source": [
    "### 1.3.1.1 对象"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "contrary-calgary",
   "metadata": {},
   "source": [
    "在 Python 中一切都是对象，就像在现实世界中一切都是对象。\n",
    "\n",
    "- 在现实中：对象可以是有型的，例如一粒米、一名学生、一辆汽车，甚至一个星球。它也可以是无形的，例如一次演出，一场球赛，一次出差。对象可以简单也可以复杂，复杂的对象可以由许多简单的对象构成，整个世界也可以被认为是一个非常复杂的对象。\n",
    "\n",
    "- 在 Python 中：对象可以是有型的，例如一个常量，一个变量，一个序列或字典。它也可以是无形的，例如一个函数。对象可以简单也可以复杂，复杂的对象可以由许多的简单对象组成，整个 Python 程序也可以被当作一个对象。\n",
    "\n",
    "无论在现实中或 Python 中，对象都具有以下三个特性：\n",
    "\n",
    "- 每个对象都有一个独特的名字以区别于其他对象。\n",
    "- 有属性来描述它的某些特征。\n",
    "- 有一组操作，每个操作决定对象的一种行为。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "widespread-fourth",
   "metadata": {},
   "source": [
    "### 1.3.1.2 类"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "vocal-communication",
   "metadata": {},
   "source": [
    "类是用来定义对象的 “模板”。\n",
    "\n",
    "- 在现实中：类是一组具有相同属性和行为的对象的抽象。例如张三、李四虽然每个人有不同的性格与职业，但他们的基本特征是相似的，都有鼻子有眼能吃饭，因此我们统称他们为“人”类，而每一个人就是一个对象。\n",
    "- 在 Python 中：类是一组具有相同数据和操作的对象的对象的集合。例如“学生”类可以由学号、姓名、性别、成绩等表示其属性的数据项和对这些数据的录入、修改和显示等操作组成，而每一个特定的学生例如 XiaoHu 就是一个对象。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "recorded-irrigation",
   "metadata": {},
   "source": [
    "### 1.3.1.3 面向对象编程的特点"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "clinical-checklist",
   "metadata": {},
   "source": [
    "面向对象编程有以下几个基本特征：\n",
    "\n",
    "- 抽象：是将有关事物的特征归纳、集中的过程。通过总结不同“对象”的主要特性设计一个“类”，只强调感兴趣的信息，忽略了与主题无关的信息。\n",
    "- 封装：是把数据和操作集中在对象内部，并尽可能隐藏对象的内部细节。对象像一个黑匣子，你只要知道它提供的功能，不需要了解其内部的实现方式。\n",
    "- 继承：是指一个类可以继承另一个类的特征与功能，并添加自己的特征。例如“吉士堡”继承了“汉堡”类，它有面包、菜与肉，但也有独特的一片芝士。\n",
    "- 多态：指不同的对象进行相同操作时产生多种不同的行为方式。例如“打开”电风扇它会旋转，“打开”电脑屏幕会亮，“打开”抽屉柜子门会开，同样是打开操作，不同对象收到指令后的行为方式是不同的。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "automotive-draft",
   "metadata": {},
   "source": [
    "## 1.3.2 Python 面向对象编程"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "czech-miniature",
   "metadata": {},
   "source": [
    "到目前为止，我们接触的变量、运算符、函数等概念来源于 “面向过程” 的编程方式。在上一节中，你可能会对 names.append('Cryin') 这种写法感到疑惑，为什么序列变量 names 可以通过符号 . 调用 append 函数？这种编程方式便是面向对象编程，在这里 names 是一个对象，对象拥有很多类似 append 的函数，每个对象都属于某一个类。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "brilliant-shock",
   "metadata": {},
   "source": [
    "下面我们将介绍 Python 中的面向对象编程方法，并以上一节中的学生成绩管理系统为例方便大家理解。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "absent-elite",
   "metadata": {},
   "source": [
    "### 1.3.2.1 Python 类与对象"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "indian-playback",
   "metadata": {},
   "source": [
    "Python 使用 class 关键字定义类，类似函数，下面的缩进部分构成了类的主体："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "whole-translation",
   "metadata": {},
   "outputs": [],
   "source": [
    "## 创建一个 student 类\n",
    "class student():\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "convertible-alias",
   "metadata": {},
   "source": [
    "使用类的名字和一对括号可以创建类的对象："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "marked-hello",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class '__main__.student'>\n",
      "<class '__main__.student'>\n"
     ]
    }
   ],
   "source": [
    "## 使用 类的名字 student 与 括号() 可以创建类的对象 xiaohu\n",
    "xiaohu = student()\n",
    "xiaoming = student()\n",
    "\n",
    "print(type(xiaohu))\n",
    "print(type(xiaoming))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "prerequisite-ideal",
   "metadata": {},
   "source": [
    "### 1.3.2.2 类与对象中的变量"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "injured-difference",
   "metadata": {},
   "source": [
    "我们提到类与对象都有包含一组属性与方法，在 Python 中类的变量用于表示类的属性。student 表示学生类，在我们的系统中我们只关注学生的姓名、数学成绩和语文成绩而不考虑其他，分别用类变量 name math_score language_score 表示。这体现了面向对象编程的”抽象性“。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "severe-reset",
   "metadata": {},
   "outputs": [],
   "source": [
    "## 创建一个 student 类\n",
    "class student():\n",
    "    ## 类的内部定义三个内部变量，并定义他们的初始值\n",
    "    name = 'Undifined'\n",
    "    math_score = -1\n",
    "    language_score = -1"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "distant-lighting",
   "metadata": {},
   "source": [
    "在 Python 中对象拥有与类相同的数据和操作，因此通过类创建的对象也拥有相同的变量。我们使用 . 符号来引用对象或类的变量与函数:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "manual-montreal",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Undifined\n",
      "-1\n",
      "-1\n"
     ]
    }
   ],
   "source": [
    "## 使用 类的名字 student 与 括号() 可以创建类的对象 xiaohu\n",
    "xiaohu = student()\n",
    "## 使用 . 符号引用对象xiaohu的变量name、math_score、language_score\n",
    "print(xiaohu.name)\n",
    "print(xiaohu.math_score)\n",
    "print(xiaohu.language_score)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "valid-attribute",
   "metadata": {},
   "source": [
    "这里我们通过类创建对象还仅仅是一个初始值，这里我们可以通过赋值符号改变对象内数据的值："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "black-pakistan",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "XiaoHu\n",
      "65\n",
      "55\n"
     ]
    }
   ],
   "source": [
    "## 通过赋值符号改变对象内变量的值\n",
    "xiaohu.name = 'XiaoHu'\n",
    "xiaohu.math_score = 65\n",
    "xiaohu.language_score = 55\n",
    "\n",
    "print(xiaohu.name)\n",
    "print(xiaohu.math_score)\n",
    "print(xiaohu.language_score)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "removed-warren",
   "metadata": {},
   "source": [
    "在这里我们要注意区分两个概念，类变量与对象变量，在上述代码中 student.name 是类变量，xiaohu.name 是对象变量。\n",
    "\n",
    "- 类变量属于类，更改类变量会影响所有后续由该类创建对象的属性。\n",
    "- 对象变量属于对象，更改对象变量只影响该对象的属性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "south-tongue",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "XiaoMing\n",
      "XiaoHu\n"
     ]
    }
   ],
   "source": [
    "## 更改对象变量只影响该对象的属性。\n",
    "xiaoming = student()\n",
    "## 修改 xiaoming.name，xiaohu 的属性不受影响\n",
    "xiaoming.name = 'XiaoMing'\n",
    "print(xiaoming.name)\n",
    "print(xiaohu.name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "loose-albuquerque",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Undifined\n",
      "Change Name\n"
     ]
    }
   ],
   "source": [
    "## 更改类变量会影响所有后续由该类创建对象的属性。\n",
    "xiaoming = student()\n",
    "print(xiaoming.name)\n",
    "\n",
    "## 修改 student.name 再次创建新对象 xiaoming\n",
    "student.name = 'Change Name'\n",
    "xiaoming = student()\n",
    "\n",
    "## xiaoming.name 不再是 undefined 而是 change name\n",
    "print(xiaoming.name)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "elder-memorial",
   "metadata": {},
   "source": [
    "### 1.3.2.3 类与对象中的函数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "earlier-integer",
   "metadata": {},
   "source": [
    "在 Python 中类函数用于表示类的操作，它又被称作为“方法”。它们与之前我们学到的函数类似，但是类函数必须有一个额外的 self 参数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "heavy-jewel",
   "metadata": {},
   "outputs": [],
   "source": [
    "class student():\n",
    "    ## 定义类函数时要有一个特殊的 self 参数\n",
    "    def print_name(self,):\n",
    "        print(self.name)\n",
    "        \n",
    "    name = 'Undifined'\n",
    "    math_score = -1\n",
    "    language_score = -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "occasional-paint",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Xiaohu\n"
     ]
    }
   ],
   "source": [
    "xiaohu = student()\n",
    "xiaohu.name = 'Xiaohu'\n",
    "xiaohu.print_name()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "authentic-williams",
   "metadata": {},
   "source": [
    "self 函数用于在类的内部指向对象本身，它是用于连接 类 与 对象 的工具，也是 Python 面向对象编程“多态”特性的一种体现。\n",
    "\n",
    "例如在上述代码，我们使用 student 类产生对象 xiaohu，那么 self 就代指 xiaohu；如果我们产生对象 xiaoming，那么 self 就会自动代指 xiaohu。因此 self 参数可以根据不同对象产生不同操作，这体现了面向对象编程的“多态性”。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "daily-impact",
   "metadata": {},
   "source": [
    "我们还可以给 student 创建一个用于更改成绩的函数，这样我们后续就不需要通过赋值符号更改对象内的数据："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "colonial-craps",
   "metadata": {},
   "outputs": [],
   "source": [
    "class student():\n",
    "    ## 定义一个修改对象数据值的函数\n",
    "    def change_score(self, course_name, score):\n",
    "        if course_name == 'math':\n",
    "            self.math_score = score\n",
    "        if course_name == 'language':\n",
    "            self.language_score = score\n",
    "        ## 如果输入的 course_name 不是 math 或者 language，则输出错误信息\n",
    "            print(course_name, \" course is still not in current system\")\n",
    "    \n",
    "    def print_name(self,):\n",
    "        print(self.name)\n",
    "        \n",
    "    name = 'Undifined'\n",
    "    math_score = -1\n",
    "    language_score = -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "split-burner",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "language  course is still not in current system\n"
     ]
    }
   ],
   "source": [
    "xiaohu = student()\n",
    "xiaohu.name = 'Xiaohu'\n",
    "xiaohu.change_score('math', 65)\n",
    "xiaohu.change_score('language',55)\n",
    "xiaohu.change_score('physics',48)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "pointed-asset",
   "metadata": {},
   "source": [
    "随着系统的迭代，系统的复杂度将会直线上升。假设当我们有了十多种课程后，采用 change_score 函数要比直接为一个个课程的成绩赋值更加优雅，用户不再需要了解 student 类中有定义哪些变量等复杂细节，只需要了解 change_score 函数的用法便可以更改学生成绩，这体现了面向对象编程的“封装性”。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fantastic-inspector",
   "metadata": {},
   "source": [
    "### 1.3.2.4 \\_\\_init\\_\\_ 方法"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "surprised-jimmy",
   "metadata": {},
   "source": [
    "在之前的代码中，我们采用赋值符号来为对象产生初始值：\n",
    "\n",
    "    xiaohu.name = 'XiaoHu'\n",
    "    xiaohu.math_score = 65\n",
    "    xiaohu.language_score = 55\n",
    "    \n",
    "然而这种方式或许有些麻烦，其实 Python 类中有一种 \\_\\_init\\_\\_ 方法专门用于初始化对象。这个方法在通过类创建对象时被自动调用，并按照你的想法初始化该对象。下面我们通过 \\_\\_init\\_\\_ 方法重新定义 student 类：\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "id": "standard-american",
   "metadata": {},
   "outputs": [],
   "source": [
    "class student():\n",
    "    ## 定义 __init__ 方法，通过该方法的参数输入初始值，在该方法内部为变量赋值\n",
    "    def __init__(self, name, math_score, language_score):\n",
    "        self.name = name\n",
    "        self.math_score = math_score\n",
    "        self.language_score = language_score\n",
    "    \n",
    "    def change_score(self, course_name, score):\n",
    "        if course_name == 'math':\n",
    "            self.math_score = score\n",
    "        elif course_name == 'language':\n",
    "            self.language_score = score\n",
    "        ## 如果输入的 course_name 不是 math 或者 language，则输出错误信息\n",
    "        else:\n",
    "            print(course_name, \" course is still not in current system\")\n",
    "    \n",
    "    def print_name(self,):\n",
    "        print(self.name)\n",
    "    \n",
    "    name = 'Undifined'\n",
    "    math_score = -1\n",
    "    language_score = -1"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "american-swiss",
   "metadata": {},
   "source": [
    "在定义了 \\_\\_init\\_\\_ 方法后，我们通过在类后面的小括号内传递参数的方式初始化对象："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "level-status",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "XiaoHu\n"
     ]
    }
   ],
   "source": [
    "## \n",
    "xiaohu = student('XiaoHu',65,55)\n",
    "xiaohu.print_name()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "incorporate-taxation",
   "metadata": {},
   "source": [
    "## 1.3.3 万物皆对象"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "uniform-abortion",
   "metadata": {},
   "source": [
    "对象是 Python 中最核心的概念，犹如道教中 “一生二，二生三，三生万物”，Python 中万物皆源于对象。下面我们在面向对象编程的角度回顾之前学习的变量、函数以及数据结构。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "neither-studio",
   "metadata": {},
   "source": [
    "### 1.3.3.1 重识变量"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "nasty-fellowship",
   "metadata": {},
   "source": [
    "在 Python 中所有变量都是对象，下面我们创建一个 int 变量，它有 bit_lenth, conjugate, to_byte, from_byte 等方法。我们测试一下 to_byte 方法： "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "reasonable-caribbean",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "int"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "variable = 1\n",
    "type(variable)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "above-convention",
   "metadata": {},
   "source": [
    "to_byte 将 int 变量转化成 byte 对象 b'\\x00x\\01' 因为整数 1 的二进制编码是 0001。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "freelance-briefing",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "b'\\x00\\x01'\n",
      "<class 'bytes'>\n"
     ]
    }
   ],
   "source": [
    "variable_byte = variable.to_bytes(2, byteorder = 'big')\n",
    "print(variable_byte)\n",
    "print(type(variable_byte))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7e65e272",
   "metadata": {},
   "source": [
    "### 1.3.3.2 重识常量"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15c1784c",
   "metadata": {},
   "source": [
    "Python 中的常量也是对象，其中最常用到对象方法的是字符串常量。\n",
    "\n",
    "字符串常用方法如下：\n",
    "- format(): 用于从其他信息中构造字符串。\n",
    "- replace(): 用于替代字符串中的某个字符或子串。\n",
    "- split(): 用于通过某种字符分隔字符串。\n",
    "- upper(): 把字符串转换成大写。\n",
    "- lower(): 把字符串转化成小写。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c94eed80",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Learn Python in a smart way!!\n",
      "Learn PHP in a hard way!!\n"
     ]
    }
   ],
   "source": [
    "## format 方法使用 {数字 i} 对应 (第i个变量) 来控制用于构造字符串的参数 \n",
    "print(\"Learn {0} in a {1} way!!\".format('Python','smart'))\n",
    "print(\"Learn {0} in a {1} way!!\".format('PHP','hard'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "ac2c2093",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Learn Python in a hard way!!\n"
     ]
    }
   ],
   "source": [
    "## replace 方法使用一个或多个参数分隔字符串，并返回子串构成的序列\n",
    "print(\"Learn Python in a smart way!!\".replace('smart','hard'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "a05cff81",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['Learn', 'Python', 'in', 'a', 'smart', 'way!!']\n"
     ]
    }
   ],
   "source": [
    "## split 方法使用一个或多个参数分隔字符串，并返回子串构成的序列\n",
    "print(\"Learn Python in a smart way!!\".split(' '))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "3f916203",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "LEARN PYTHON IN A SMART WAY!!\n",
      "learn python in a smart way!!\n"
     ]
    }
   ],
   "source": [
    "## upper 和 lower 方法转化大小写\n",
    "print(\"Learn Python in a smart way!!\".upper())\n",
    "print(\"Learn Python in a smart way!!\".lower())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "devoted-cedar",
   "metadata": {},
   "source": [
    "### 1.3.3.2 重识函数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "pharmaceutical-district",
   "metadata": {},
   "source": [
    "更神奇的是，在 Python 中函数也是对象，因此函数也有自己的数据与方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "killing-modern",
   "metadata": {},
   "outputs": [],
   "source": [
    "def check_sum(num1, num2, target):\n",
    "    ## 在 def xxx(): 下面缩进的是函数的内容\n",
    "    a = num1\n",
    "    b = num2\n",
    "    return a + b == target"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "tight-generation",
   "metadata": {},
   "source": [
    "通过 \\.\\_\\_name\\_\\_ 方法可以获得函数的名字："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "extensive-firmware",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'check_sum'"
      ]
     },
     "execution_count": 74,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "check_sum.__name__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "modern-sewing",
   "metadata": {},
   "source": [
    "### 1.3.3.3 重识数据结构"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "willing-parks",
   "metadata": {},
   "source": [
    "现在你可以想象到，数据结构也理所应当是对象。是的，数据结构为我们提供了许多非常的方法！上一节中的 append 就是其中一个。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "id": "soviet-determination",
   "metadata": {},
   "outputs": [],
   "source": [
    "l = [1,2,3,4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "id": "weighted-ordinance",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3, 4, 5]\n"
     ]
    }
   ],
   "source": [
    "l.append(5)\n",
    "print(l)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "conceptual-richardson",
   "metadata": {},
   "source": [
    "除此之外，我们可以通过 pop 方法替代 del 关键字删除序列内某个元素："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "id": "american-continent",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2, 3, 4, 5]\n"
     ]
    }
   ],
   "source": [
    "l.pop(1)\n",
    "print(l)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "broke-atmosphere",
   "metadata": {},
   "source": [
    "通过 insert 方法在特定位置增加元素："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "id": "metropolitan-conference",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3, 4, 5]\n"
     ]
    }
   ],
   "source": [
    "## 第一个参数是位置，第二个参数是插入的元素\n",
    "l.insert(0,1)\n",
    "print(l)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "corrected-seeking",
   "metadata": {},
   "source": [
    "同样的，在元组、字典、集合等数据结构中也提供了很多方法，在此将常用的方法总结如下："
   ]
  },
  {
   "cell_type": "markdown",
   "id": "liberal-drive",
   "metadata": {},
   "source": [
    "- 列表\n",
    "    - append(x) 把元素 x 放在入列表尾部\n",
    "    - count(x) 统计元素 x 在列表中出现次数\n",
    "    - extent(seq) 把新列表 seq 合并到列表尾部\n",
    "    - index(x) 返回元素 x 在列表第一次出现的位置\n",
    "    - insert(index, x) 把元素 x 插入到 index 位置\n",
    "    - pop(index) 删除并返回 index 所在位置的元素\n",
    "    - remove(x) 删除出现的第一个 x 元素\n",
    "    - reverse() 颠倒列表顺序\n",
    "    - sort() 对列表进行排序\n",
    "    \n",
    "    \n",
    "- 字典\n",
    "    - clear() 清楚字典内所有元素\n",
    "    - copy() 返回字典的一个复制\n",
    "    - has_key(key) 检查 key 是否在字典中 \n",
    "    - items() 返回一个含由 (key, value) 格式元组构成的列表\n",
    "    - keys() 返回由键构成列表\n",
    "    - values() 返回由值构成的列表\n",
    "    - setdefault(key, default) 为键 key 添加默认值 default\n",
    "    - pop(key) 删除 key 并返回对应的值\n",
    "    \n",
    "    \n",
    "- 集合\n",
    "    - add(x) 向集合中添加元素 x\n",
    "    - clear() 清空集合\n",
    "    - copy() 返回集合的一个复制\n",
    "    - difference(set) 返回集合与另一个集合的差集 \n",
    "    - discard(x) 删除元素 x \n",
    "    - isdisjoint(set) 判断两个集合是否有交集 \n",
    "    - issubset(set) 判断新集合 set 是否是集合的子集\n",
    "    - issuperset() 判断新集合 set 是否是集合的超集"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "massive-selection",
   "metadata": {},
   "source": [
    "### 1.3.3.4 重识程序"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "departmental-major",
   "metadata": {},
   "source": [
    "在某种意义上，我们也可以认为 Python 程序是一个对象，它也有自己的数据和方法。其中 \\_\\_name\\_\\_ 就是它的一个变量，我们并没有定义过这个变量，但由于它是程序的对象变量，因此可以直接调用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "id": "regulated-speed",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'__main__'"
      ]
     },
     "execution_count": 89,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "__name__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "characteristic-persian",
   "metadata": {},
   "source": [
    "## 1.3.4 练习"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "engaged-ribbon",
   "metadata": {},
   "source": [
    "### 1.3.4.1 重构成绩管理系统\n",
    "\n",
    "\n",
    "<blockquote>\n",
    "    \n",
    "此练习是开放题，使用 面向对象 的编程方法重构之前的成绩管理系统，并完成之前的任务。\n",
    "\n",
    "Task 1. 在上一次期末考试中，XiaoHu 考了数学 65 分，语文 55 分；XiaoMing 考了数学 80 分，语文92 分；XiaoWei 考了数学 95 分，语文 98 分，以此建立学生成绩管理系统。\n",
    "\n",
    "Task 2. 在本次期末考试中，XiaoHu 考了数学 95 分，语文 85 分；XiaoMing 考了数学 75 分，语文 71 分；XiaoWei 考了数学 92 分，语文 93 分，以此对之前的成绩进行更新。\n",
    "\n",
    "Task 3. 由于 XiaoMing 的成绩出现了大幅度下滑，家长决定要 XiaoMing 转学到另一所高中，以此在系统中删除 XiaoMing 的信息。\n",
    "\n",
    "Task 4. 学校新转来的学生 Cryin 本次考试成绩为 数学 87 分，语文 88 分，在系统中录入 Cryin 的成绩。\n",
    "\n",
    "</blockquote>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "id": "direct-stick",
   "metadata": {},
   "outputs": [],
   "source": [
    "class student():\n",
    "    def __init__(self, name, math_score, language_score):\n",
    "        self.name = name\n",
    "        self.math_score = math_score\n",
    "        self.language_score = language_score\n",
    "    \n",
    "    ## repr 函数用于定义对象被输出时的输出结果\n",
    "    def __repr__(self):\n",
    "        return str((self.name, self.math_score, self.language_score))\n",
    "    \n",
    "    def change_score(self, course_name, score):\n",
    "        if course_name == 'math':\n",
    "            self.math_score = score\n",
    "        elif course_name == 'language':\n",
    "            self.language_score = score\n",
    "        else:\n",
    "            print(course_name, \" course is still not in current system\")\n",
    "    \n",
    "    def print_name(self,):\n",
    "        print(self.name)\n",
    "    \n",
    "    name = 'Undifined'\n",
    "    math_score = -1\n",
    "    language_score = -1"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "solid-sequence",
   "metadata": {},
   "source": [
    "之前我们实现了学生类，现在我们通过把学生对象保存在字典中实现一个成绩系统。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "id": "available-exhibition",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'XiaoHu': ('XiaoHu', 65, 55), 'XiaoMing': ('XiaoMing', 80, 92), 'XiaoWei': ('XiaoHu', 95, 98)}\n",
      "{'XiaoHu': ('XiaoHu', 95, 85), 'XiaoMing': ('XiaoMing', 75, 71), 'XiaoWei': ('XiaoHu', 92, 93)}\n",
      "{'XiaoHu': ('XiaoHu', 95, 85), 'XiaoWei': ('XiaoHu', 92, 93)}\n",
      "{'XiaoHu': ('XiaoHu', 95, 85), 'XiaoWei': ('XiaoHu', 92, 93), 'Cryin': ('Cryin', 87, 88)}\n"
     ]
    }
   ],
   "source": [
    "## Task1\n",
    "ab = {}\n",
    "ab.setdefault('XiaoHu', student('XiaoHu', 65, 55))\n",
    "ab.setdefault('XiaoMing', student('XiaoMing', 80, 92))\n",
    "ab.setdefault('XiaoWei', student('XiaoHu', 95, 98))\n",
    "print(ab)\n",
    "\n",
    "## Task2\n",
    "ab['XiaoHu'].change_score('math', 95)\n",
    "ab['XiaoMing'].change_score('math', 75)\n",
    "ab['XiaoWei'].change_score('math', 92)\n",
    "\n",
    "ab['XiaoHu'].change_score('language', 85)\n",
    "ab['XiaoMing'].change_score('language', 71)\n",
    "ab['XiaoWei'].change_score('language', 93)\n",
    "print(ab)\n",
    "\n",
    "## Task3\n",
    "ab.pop('XiaoMing')\n",
    "print(ab)\n",
    "\n",
    "## Task4\n",
    "ab.setdefault('Cryin', student('Cryin', 87, 88))\n",
    "print(ab)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.2"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": true,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "218.55978393554688px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
